<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JSON数据表格展示</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: Arial, sans-serif;
            height: 100vh;
            display: flex;
            flex-direction: column;
            background-color: #f5f5f5;
        }
        
        .table-container {
            flex: 1;
            overflow: auto;
            padding: 10px;
            background: white;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            display: flex;
            flex-direction: column;
            height: calc(100vh - 20px);
        }
        
        .table-wrapper {
            flex: 1;
            overflow: auto;
            min-height: 0;
            position: relative;
        }
        
        /* 自定义滚动条样式 - 默认不显示，只在需要时显示，并缩小尺寸 */
        .table-wrapper::-webkit-scrollbar {
            width: 8px;
            height: 8px;
            opacity: 0;
            transition: opacity 0.3s ease;
        }
        
        .table-wrapper::-webkit-scrollbar-track {
            background: #f1f1f1;
            border-radius: 4px;
        }
        
        .table-wrapper::-webkit-scrollbar-thumb {
            background: #c1c1c1;
            border-radius: 4px;
        }
        
        .table-wrapper::-webkit-scrollbar-thumb:hover {
            background: #a8a8a8;
        }
        
        /* 当获得焦点或有滚动时显示滚动条 */
        .table-wrapper:focus::-webkit-scrollbar,
        .table-wrapper:hover::-webkit-scrollbar,
        .table-wrapper.scrollable::-webkit-scrollbar {
            opacity: 1;
        }
        
        table {
            width: 100%;
            border-collapse: collapse;
            font-size: 10px;
            min-width: 100%;
        }
        
        th, td {
            padding: 6px 8px;
            text-align: left;
            border-bottom: 1px solid #ddd;
            white-space: nowrap;
            font-size: 10px;
        }
        
        th {
            background-color: #f8f9fa;
            font-weight: bold;
            position: sticky;
            top: 0;
            z-index: 10;
            cursor: pointer;
            user-select: none;
        }
        
        th:hover {
            background-color: #e9ecef;
        }
        
        th.sortable::after {
            content: ' ↕';
            color: #aaa;
            font-size: 8px;
        }
        
        th.sort-asc::after {
            content: ' ↑';
            color: #333;
        }
        
        th.sort-desc::after {
            content: ' ↓';
            color: #333;
        }
        
        tr:hover {
            background-color: #f5f5f5;
        }
        
        .category-header {
            background-color: #e9ecef !important;
            font-weight: bold;
            position: sticky;
            left: 0;
            z-index: 20;
        }
        
        .category-cell {
            background-color: #f8f9fa;
            font-weight: bold;
            position: sticky;
            left: 0;
            z-index: 15;
        }
        
        .row-number {
            text-align: center;
            font-size: 10px;
            width: 40px;
            position: sticky;
            left: 0;
            z-index: 5;
            background-color: white;
        }
        
        .row-number.category-cell {
            z-index: 20;
            background-color: #e9ecef;
        }
        
        /* 交替行颜色 */
        tr:nth-child(even) {
            background-color: #f9f9f9;
        }

        tr:nth-child(odd) {
            background-color: white;
        }
        
        tr:hover {
            background-color: #f0f0f0 !important;
        }
        
        .no-data {
            text-align: center;
            padding: 40px;
            color: #666;
            font-size: 10px;
        }
        
        /* 总记录数样式 - 放置在左下方，12px字体，不加粗 */
        .total-records {
            position: absolute;
            left: 10px;
            bottom: 10px;
            font-size: 12px;
            color: #333;
            font-weight: normal;
            background-color: rgba(255, 255, 255, 0.8);
            padding: 4px 8px;
            border-radius: 3px;
            z-index: 100;
        }
    </style>
</head>
<body>
    <div class="table-container">
        <div class="table-wrapper" id="tableWrapper" tabindex="0">
            <table id="dataTable">
                <!-- 表格内容将在这里动态生成 -->
            </table>
            <!-- 总记录数显示在左下方 -->
            <div class="total-records" id="totalRecords">总记录数: 0</div>
        </div>
    </div>

    <script>
        // 全局变量
        let jsonData = [];
        let categories = [];
        let currentPage = 1;
        let pageSize = 25;
        let headers = [];
        let detectedTypes = {};
        let categoryField = '';
        let sortColumn = null;
        let sortDirection = 'asc';
        let totalPages = 1;

        /**
         * 加载JSON数据并生成表格
         * @param {Array|Object} data - JSON数据，可以是数组或对象
         */
        function loadJSON(data) {
            // 确保数据是数组格式
            if (!Array.isArray(data)) {
                jsonData = Array.isArray(data) ? data : [data];
            } else {
                jsonData = data;
            }
            
            if (jsonData.length === 0) {
                renderTable([]);
                return;
            }
            
            // 自动识别表头和数据类型
            analyzeData();
            
            // 尝试自动识别分类字段（第一个字符串类型的字段）
            detectCategoryField();
            
            // 渲染表格
            renderTable(jsonData);
        }

        /**
         * 分析数据，识别表头和字段类型
         */
        function analyzeData() {
            if (jsonData.length === 0) return;
            
            // 使用第一行数据确定表头和类型
            const firstRow = jsonData[0];
            headers = Object.keys(firstRow);
            
            // 检测每个字段的类型
            detectedTypes = {};
            headers.forEach(header => {
                const value = firstRow[header];
                detectedTypes[header] = detectType(value);
            });
        }

        /**
         * 检测值的类型
         * @param {*} value - 要检测的值
         * @returns {string} 类型名称
         */
        function detectType(value) {
            if (value === null || value === undefined) return 'null';
            if (typeof value === 'number') return Number.isInteger(value) ? 'integer' : 'float';
            if (typeof value === 'boolean') return 'boolean';
            if (typeof value === 'string') {
                // 检查是否是日期格式
                if (isDateString(value)) return 'date';
                return 'string';
            }
            if (Array.isArray(value)) return 'array';
            if (typeof value === 'object') return 'object';
            return 'string';
        }

        /**
         * 检查字符串是否可能是日期格式
         * @param {string} str - 字符串值
         * @returns {boolean} 是否为日期
         */
        function isDateString(str) {
            // 简单的日期格式检测
            const datePatterns = [
                /^\d{4}-\d{2}-\d{2}$/,
                /^\d{4}\/\d{2}\/\d{2}$/,
                /^\d{4}-\d{2}-\d{2}T/,
                /^\d{10}$/, // Unix时间戳
                /^\d{13}$/  // Unix时间戳(毫秒)
            ];
            return datePatterns.some(pattern => pattern.test(str));
        }

        /**
         * 检测可能的分类字段
         */
        function detectCategoryField() {
            // 优先选择字符串类型的字段作为分类字段
            for (const header of headers) {
                if (detectedTypes[header] === 'string') {
                    // 检查该字段的值是否具有较少的唯一值（适合作为分类）
                    const uniqueValues = new Set(jsonData.map(item => item[header])).size;
                    if (uniqueValues <= Math.min(20, jsonData.length / 5)) {
                        categoryField = header;
                        return;
                    }
                }
            }
            // 如果没有找到合适的字符串字段，选择第一个字段
            categoryField = headers[0];
        }

        /**
         * 渲染表格
         * @param {Array} data - 要渲染的数据
         */
        function renderTable(data) {
            if (!data || data.length === 0) {
                document.getElementById('dataTable').innerHTML = '<tr><td colspan="100%" class="no-data">暂无数据</td></tr>';
                document.getElementById('totalRecords').textContent = '总记录数: 0';
                return;
            }

            // 如果指定了分类字段，对数据进行分类分组
            if (categoryField && detectedTypes[categoryField] === 'string') {
                groupDataByCategory(data);
            } else {
                categories = [{ name: '全部', items: data }];
            }

            generateTableHTML();
            
            // 显示总记录数（12px字体，不加粗），放在左下方
            const totalRecords = categories.reduce((sum, category) => sum + category.items.length, 0);
            document.getElementById('totalRecords').textContent = `总记录数: ${totalRecords}`;
            
            // 设置表格容器的滚动状态
            const tableWrapper = document.getElementById('tableWrapper');
            if (data.length > 0) {
                // 检查内容是否超出容器，如果是则添加scrollable类以显示滚动条
                setTimeout(() => {
                    if (tableWrapper.scrollHeight > tableWrapper.clientHeight) {
                        tableWrapper.classList.add('scrollable');
                    }
                }, 100);
            }
        }

        /**
         * 按分类字段对数据进行分组
         * @param {Array} data - 原始数据
         */
        function groupDataByCategory(data) {
            const categoryMap = {};
            
            data.forEach(item => {
                const categoryValue = item[categoryField] || '未分类';
                if (!categoryMap[categoryValue]) {
                    categoryMap[categoryValue] = [];
                }
                categoryMap[categoryValue].push(item);
            });

            // 转换为数组并按分类名称排序
            categories = Object.keys(categoryMap)
                .sort()
                .map(name => ({
                    name: name,
                    items: categoryMap[name]
                }));
        }

        /**
         * 生成表格HTML
         */
        function generateTableHTML() {
            const table = document.getElementById('dataTable');
            let html = '<thead><tr>';
            
            // 生成表头（增加行号列）
            html += '<th class="row-number"></th>'; // 行号列头
            headers.forEach(header => {
                const sortClass = header === sortColumn ? `sort-${sortDirection}` : 'sortable';
                html += `<th class="${sortClass}" onclick="sortTable('${header}')">${header}</th>`;
            });
            html += '</tr></thead><tbody>';
            
            // 生成表格内容
            let rowCount = 0;
            
            categories.forEach(category => {
                if (category.items.length === 0) return;
                
                // 添加分类标题行
                if (category.name !== '全部') {
                    html += `<tr class="category-header"><td class="category-cell row-number"></td><td class="category-cell" colspan="${headers.length}"><strong>${category.name}</strong></td></tr>`;
                }
                
                // 添加该分类下的数据行
                category.items.forEach((item, index) => {
                    rowCount++;
                    
                    html += '<tr>';
                    // 行号
                    html += `<td class="row-number">${rowCount}</td>`;
                    
                    // 数据列
                    headers.forEach(header => {
                        const value = item[header];
                        const type = detectedTypes[header] || 'string';
                        html += `<td>${formatValue(value, type)}</td>`;
                    });
                    html += '</tr>';
                });
            });
            
            html += '</tbody>';
            table.innerHTML = html || '<tr><td colspan="100%" class="no-data">暂无数据</td></tr>';
        }

        /**
         * 表格排序功能
         * @param {string} column - 要排序的列名
         */
        function sortTable(column) {
            // 如果点击的是当前排序列，则切换排序方向
            if (sortColumn === column) {
                sortDirection = sortDirection === 'asc' ? 'desc' : 'asc';
            } else {
                // 否则设置新的排序列和默认升序
                sortColumn = column;
                sortDirection = 'asc';
            }
            
            // 对数据进行排序
            jsonData.sort((a, b) => {
                const valueA = a[column];
                const valueB = b[column];
                const type = detectedTypes[column] || 'string';
                
                let comparison = 0;
                
                // 根据类型进行比较
                switch (type) {
                    case 'number':
                    case 'integer':
                    case 'float':
                        comparison = (parseFloat(valueA) || 0) - (parseFloat(valueB) || 0);
                        break;
                    case 'boolean':
                        comparison = (valueA === valueB) ? 0 : (valueA ? 1 : -1);
                        break;
                    case 'date':
                        const dateA = parseDate(valueA);
                        const dateB = parseDate(valueB);
                        comparison = (dateA || new Date(0)) - (dateB || new Date(0));
                        break;
                    case 'string':
                        comparison = String(valueA || '').localeCompare(String(valueB || ''));
                        break;
                    default:
                        comparison = String(valueA || '').localeCompare(String(valueB || ''));
                }
                
                return sortDirection === 'asc' ? comparison : -comparison;
            });
            
            // 重新应用当前的分类字段
            if (categoryField && detectedTypes[categoryField] === 'string') {
                groupDataByCategory(jsonData);
            } else {
                categories = [{ name: '全部', items: jsonData }];
            }
            
            // 重置到第一页（虽然不分页，但保持逻辑一致性）
            currentPage = 1;
            
            // 重新渲染表格
            renderTable(jsonData);
        }

        /**
         * 格式化值显示
         * @param {*} value - 值
         * @param {string} type - 类型
         * @returns {string} 格式化后的值
         */
        function formatValue(value, type) {
            if (value === null || value === undefined) return '';
            
            switch (type) {
                case 'boolean':
                    return value ? '是' : '否';
                case 'date':
                    // 尝试解析日期
                    const date = parseDate(value);
                    return date ? date.toLocaleString() : value;
                case 'integer':
                case 'float':
                    return Number(value).toLocaleString();
                case 'array':
                    return Array.isArray(value) ? value.join(', ') : value;
                case 'object':
                    return typeof value === 'object' ? JSON.stringify(value) : value;
                default:
                    return String(value);
            }
        }

        /**
         * 尝试解析日期字符串
         * @param {string} value - 日期字符串
         * @returns {Date|null} 日期对象或null
         */
        function parseDate(value) {
            // 尝试多种日期格式
            const dateFormats = [
                { regex: /^(\d{4})-(\d{2})-(\d{2})$/, handler: (m) => new Date(parseInt(m[1]), parseInt(m[2]) - 1, parseInt(m[3])) },
                { regex: /^(\d{4})\/(\d{2})\/(\d{2})$/, handler: (m) => new Date(parseInt(m[1]), parseInt(m[2]) - 1, parseInt(m[3])) },
                { regex: /^(\d{10})$/, handler: (m) => new Date(parseInt(m[1]) * 1000) },
                { regex: /^(\d{13})$/, handler: (m) => new Date(parseInt(m[1])) }
            ];
            
            for (const format of dateFormats) {
                const match = value.match(format.regex);
                if (match) {
                    try {
                        return format.handler(match);
                    } catch (e) {
                        continue;
                    }
                }
            }
            
            return null;
        }

        /**
         * 下载CSV文件
         * 文件名自带时间戳，格式为：data_YYYYMMDD_HHMMSS.csv
         * 此函数可被外部JavaScript调用
         */
        window.downloadCSV = function() {
            if (jsonData.length === 0 && categories.length === 0) {
                alert('没有数据可下载');
                return;
            }
            
            // 获取要导出的所有数据（扁平化处理分类数据）
            let exportData = [];
            
            if (categories.length > 0) {
                // 如果有分类数据，提取所有分类中的数据项
                categories.forEach(category => {
                    exportData = exportData.concat(category.items);
                });
            } else {
                // 如果没有分类，直接使用jsonData
                exportData = jsonData;
            }
            
            if (exportData.length === 0) {
                alert('没有数据可下载');
                return;
            }
            
            // 准备CSV内容
            let csvContent = '';
            
            // 添加表头
            csvContent += headers.map(header => `"${header}"`).join(',') + '\n';
            
            // 添加数据行
            exportData.forEach(item => {
                const row = headers.map(header => {
                    const value = item[header];
                    const type = detectedTypes[header] || 'string';
                    
                    let formattedValue = '';
                    
                    // 根据类型格式化值
                    switch (type) {
                        case 'boolean':
                            formattedValue = value ? '是' : '否';
                            break;
                        case 'date':
                            // 尝试解析日期
                            const date = parseDate(value);
                            formattedValue = date ? date.toLocaleString() : value;
                            break;
                        case 'integer':
                        case 'float':
                            formattedValue = Number(value).toLocaleString();
                            break;
                        case 'array':
                            formattedValue = Array.isArray(value) ? value.join(', ') : value;
                            break;
                        case 'object':
                            formattedValue = typeof value === 'object' ? JSON.stringify(value) : value;
                            break;
                        default:
                            formattedValue = String(value);
                    }
                    
                    // 处理包含逗号、引号或换行符的值
                    if (formattedValue === null || formattedValue === undefined) {
                        return '';
                    }
                    
                    if (formattedValue.toString().includes('"') || formattedValue.toString().includes(',') || formattedValue.toString().includes('\n')) {
                        return '"' + formattedValue.toString().replace(/"/g, '""') + '"';
                    }
                    return formattedValue.toString();
                });
                csvContent += row.join(',') + '\n';
            });
            
            // 生成带时间戳的文件名
            const now = new Date();
            const year = now.getFullYear();
            const month = String(now.getMonth() + 1).padStart(2, '0');
            const day = String(now.getDate()).padStart(2, '0');
            const hours = String(now.getHours()).padStart(2, '0');
            const minutes = String(now.getMinutes()).padStart(2, '0');
            const seconds = String(now.getSeconds()).padStart(2, '0');
            
            const timestamp = `${year}${month}${day}_${hours}${minutes}${seconds}`;
            const filename = `data_${timestamp}.csv`;
            
            // 创建并下载文件
            const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' });
            const link = document.createElement('a');
            const url = URL.createObjectURL(blob);
            link.setAttribute('href', url);
            link.setAttribute('download', filename);
            link.style.visibility = 'hidden';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        };
    </script>
</body>
</html>
